// 引入 reflect-metadata 库
import "reflect-metadata";
import express, { Request, Response } from "express";
import multer from "multer";
import { File } from "node:buffer";

const app = express();
app.use(express.json());
app.use(express.static(__dirname + "/public"));

const storage = multer.diskStorage({
  destination: function (req, file, cb) {
    cb(null, "uploads/"); // 指定文件保存的目录
  },
  filename: function (req, file, cb) {
    cb(null, file.originalname); // 指定保存的文件名
  },
});

const upload = multer({ storage: storage });

function getParamNames(func: Function): string[] {
  const STRIP_COMMENTS = /((\/\/.*$)|(\/\*[\s\S]*?\*\/))/gm;
  const ARGUMENT_NAMES = /([^\s,]+)/g;
  const fnStr = func.toString().replace(STRIP_COMMENTS, "");
  const result = fnStr
    .slice(fnStr.indexOf("(") + 1, fnStr.indexOf(")"))
    .match(ARGUMENT_NAMES);
  if (result === null) return [];
  return result.map((name) => name.trim());
}

let baseUrlMap = new Map();

//实现RestController类装饰器
const RestController = (path: string): ClassDecorator => {
  return (target: Function) => {
   console.log("RestController constructor");
   console.log("target-name:",target.name);
   baseUrlMap.set(target.name, path);
  };
};

//使用express接收请求实现装饰器GetMapping
const GetMapping = (path: string): MethodDecorator => {
  return (
    target: Object,
    key: string | symbol,
    descriptor: PropertyDescriptor
  ) => {
    //获取基础路径
    console.log("target-constructor-name:",target.constructor.name);
    const bastUrl = baseUrlMap.get(target.constructor.name);
    console.log(bastUrl);
    const fnc: Function = descriptor.value;
    //获取fnc函数的参数名称列表
    const paramNames = getParamNames(fnc);
    app.get(path, (req: Request, res: Response) => {
      try {
        const reqParam = { ...req.params, ...req.query };
        let params = [];
        for (let i = 0; i < paramNames.length; i++) {
          params.push(reqParam[paramNames[i]]);
        }
        const result = fnc.call(target, ...params, res);
        if (typeof result === "string") {
          if (result.startsWith("file:")) {
            console.debug(result);
            res.download(
              result.substring(result.indexOf(":") + 1),
              function (err) {
                if (err) {
                  // 文件下载失败的处理逻辑
                  res.status(404).send("文件不存在");
                }
              }
            );
            return;
          } else if (result.startsWith("redirect:")) {
            console.debug(result);
            res.redirect(result.substring(result.indexOf(":") + 1));
            return;
          } else if (result.startsWith("json:")) {
            console.debug(result);
            res.json(result.substring(result.indexOf(":") + 1));
            return;
          } else if (result.startsWith("html:")) {
            console.debug(result);
            res.send(result.substring(result.indexOf(":") + 1));
            return;
          }
        }
        res.status(200).send(result);
      } catch (error) {
        console.error();
        if (error instanceof Error) {
          res.status(500).send(error.message);
        }
        res.status(500).send(error);
      }
    });
  };
};

//使用express接收请求实现装饰器PostMapping
const PostMapping = (
  path: string = "/",
  isFile: boolean = false
): MethodDecorator => {
  return (
    target: Object,
    key: string | symbol,
    descriptor: PropertyDescriptor
  ) => {
    const fnc: Function = descriptor.value;
    //获取fnc函数的参数名称列表
    const paramNames = getParamNames(fnc);
    // 获取fnc方法参数类型类别
    const paramTypes = Reflect.getMetadata("design:paramtypes", target, key);
    // map映射参数与对应类型
    const paramTypeMap = new Map();
    paramTypes.forEach((type: any, index: number) => {
      paramTypeMap.set(paramNames[index], type);
    });
    if (isFile) {
      app.post(path, upload.single("file"), (req: Request, res: Response) => {
        try {
          const reqParam = { ...req.params, ...req.query };
          let params: any[] = [];
          // 遍历paramTypeMap
          paramTypeMap.forEach((type: any, name: string) => {
            if (!reqParam[name] && type === File) {
              //如果reqParam[name]存在，并且为数组类型
              params.push(req.file);
            }
          });

          const result = fnc.call(target, ...params, res);
          res.status(200).send(result);
        } catch (error) {
          console.error();
          if (error instanceof Error) {
            res.status(500).send(error.message);
          }
          res.status(500).send(error);
        }
      });
      return;
    }
    app.post(path, (req: Request, res: Response) => {
      try {
        const reqParam = { ...req.params, ...req.query };
        let params: any[] = [];
        // 遍历paramTypeMap
        paramTypeMap.forEach((type: any, name: string) => {
          //如果reqParam[name]存在，并且为基本数据类型
          if (
            reqParam[name] &&
            (type === String ||
              type === Number ||
              type === Boolean ||
              type === Date)
          ) {
            params.push(reqParam[name]);
          } else if (!reqParam[name] && type === Array) {
            //如果reqParam[name]存在，并且为数组类型
            params.push(req.body);
          } else if (!reqParam[name] && type === Object) {
            //如果reqParam[name]存在，并且为对象类型
            params.push(req.body);
          }
        });

        const result = fnc.call(target, ...params, res);
        res.status(200).send(result);
      } catch (error) {
        console.error();
        if (error instanceof Error) {
          res.status(500).send(error.message);
        }
        res.status(500).send(error);
      }
    });
    return;
  };
};

export { app, Request, Response,RestController, GetMapping, PostMapping };
